/*
  AdViEmulator - AdventureVision emulator
  Copyright (C) 2012-2013  JustBurn

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "mainwindow.h"
#include "apuwindow.h"
#include "ui_apuwindow.h"

enum {
	HEXIO_PC, HEXIO_A,
	HEXIO_RAMB, HEXIO_SA, HEXIO_SB,
	HEXIO_PORTL,
	CHECK_C, CHECK_SKIPNEXT, CHECK_SKIPLBI
};

#define CONN_HEXIO(c, e) { connect(c, SIGNAL(valueChanged(int)), this, SLOT(hexioChanged(int))); c->setProperty("type", QVariant(e)); }
#define CONN_ABUTTON(c, e) { connect(c, SIGNAL(toggled(bool)), this, SLOT(abuttonChanged(bool))); c->setProperty("type", QVariant(e)); }

APUWindow::APUWindow(QWidget *parent, AdViEmulator *emu)
	: BaseViewWindow(parent)
	, refreshTmr(new QTimer(this))
	, ui(new Ui::APUWindow)
{
	ui->setupUi(this);
	avemu = emu;
	connect(refreshTmr, SIGNAL(timeout()), this, SLOT(refreshWindow()));
	connect(parent, SIGNAL(emuStateChanged(int)), this, SLOT(emuStateChanged(int)));
	connect(ui->pushStart, SIGNAL(clicked()), parent, SLOT(OnMenuStartEmu()));
	connect(ui->pushStop, SIGNAL(clicked()), parent, SLOT(OnMenuStopEmu()));
	connect(ui->pushStep, SIGNAL(clicked()), parent, SLOT(OnMenuAPUStepEmu()));
	connect(ui->pushReset, SIGNAL(clicked()), parent, SLOT(OnMenuResetEmu()));
	refreshTmr->start(500);
	ui->boxView->attachEmu(emu, ui->scrollView);
	refreshRegisters();
	setAddress = -1;
	// Connect signals
	ui->linePC->setDigits(3); ui->linePC->setMaximum(0x1FF);
	ui->lineA->setDigits(1); ui->lineA->setMaximum(15);
	ui->lineRAMB->setDigits(2); ui->lineRAMB->setMaximum(31);
	ui->lineSA->setDigits(3); ui->lineSA->setMaximum(0x1FF);
	ui->lineSB->setDigits(3); ui->lineSB->setMaximum(0x1FF);
	CONN_HEXIO(ui->linePC, HEXIO_PC);
	CONN_HEXIO(ui->lineA, HEXIO_A);
	CONN_HEXIO(ui->lineRAMB, HEXIO_RAMB);
	CONN_HEXIO(ui->lineSA, HEXIO_SA);
	CONN_HEXIO(ui->lineSB, HEXIO_SB);
	CONN_HEXIO(ui->linePortL, HEXIO_PORTL);
	CONN_ABUTTON(ui->checkC, CHECK_C);
	CONN_ABUTTON(ui->checkSkipNext, CHECK_SKIPNEXT);
	CONN_ABUTTON(ui->checkSkipLBI, CHECK_SKIPLBI);
	QTimer::singleShot(0, this, SLOT(firstWindow()));
}

APUWindow::~APUWindow()
{
	refreshTmr->stop();
	delete refreshTmr;
	delete ui;
}

void APUWindow::setAPUAddress(int addr)
{
	setAddress = addr;
}

void APUWindow::firstWindow()
{
	ui->boxView->repaint();
	if (setAddress == -1) {
		ui->boxView->moveCursor(avemu->apu.pc.w, true);
	} else {
		ui->boxView->moveCursor(setAddress, true);
	}
}

void APUWindow::refreshWindow(void)
{
	if (avemu->IsRunning() && (ui->checkFollowPC->checkState() == Qt::Checked)) {
		ui->boxView->moveCursor(avemu->apu.pc.w);
		refreshRegisters();
	}
	ui->boxView->update();
}

void APUWindow::refreshRegisters(void)
{
	ui->linePC->setValue(avemu->apu.pc.w);
	ui->lineA->setValue(avemu->apu.accu);
	ui->lineRAMB->setValue(avemu->apu.ramb);
	ui->lineSA->setValue(avemu->apu.sa);
	ui->lineSB->setValue(avemu->apu.sb);
	ui->linePortL->setValue(avemu->apu.port_l);
	ui->checkC->setChecked(avemu->apu.carry);
	ui->checkSkipNext->setChecked(avemu->apu.skipnext);
	ui->checkSkipLBI->setChecked(avemu->apu.skiplbi);
	ui->labelPortDG->setText("Output: D = " + QString::number(avemu->apu.port_d & 1) + ", G = " + QString::number(avemu->apu.port_g & 1));
}

void APUWindow::emuStateChanged(int)
{
	if (ui->checkFollowPC->checkState() == Qt::Checked) {
		ui->boxView->moveCursor(avemu->apu.pc.w);
	}
	refreshRegisters();
	refreshWindow();
}

void APUWindow::hexioChanged(int value)
{
	switch(sender()->property("type").toInt()) {
	case HEXIO_PC: avemu->apu.pc.w = value; break;
	case HEXIO_A: avemu->apu.accu = value; break;
	case HEXIO_RAMB: avemu->apu.ramb = value; break;
	case HEXIO_SA: avemu->apu.sa = value; break;
	case HEXIO_SB: avemu->apu.sb = value; break;
	case HEXIO_PORTL: avemu->apu.port_l = value; break;
	}
	refreshRegisters();
	refreshWindow();
}

void APUWindow::abuttonChanged(bool checked)
{
	switch(sender()->property("type").toInt()) {
	case CHECK_C: avemu->apu.carry = checked ? 1 : 0; break;
	case CHECK_SKIPNEXT: avemu->apu.skipnext = checked; break;
	case CHECK_SKIPLBI: avemu->apu.skiplbi = checked; break;
	}
	refreshRegisters();
	refreshWindow();
}

void APUWindow::findPC(void)
{
	ui->boxView->moveCursor(avemu->apu.pc.w, true);
	ui->boxView->update();
}

void APUWindow::goToAddress(void)
{
	bool okConv;
	int number = ui->lineAddress->text().toInt(&okConv, 16);
	if (okConv) {
		ui->boxView->moveCursor(number, true);
		ui->boxView->update();
	}
}
